package com.game.framework.dao;

import com.game.framework.common.error.EventExecutorGroup;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import lombok.extern.slf4j.Slf4j;

import java.util.Optional;

/**
 * 之后考虑使用Mongodb的异步驱动实现异步操作。
 */
@Slf4j
public abstract class AbstractAsyncDao<Entity,ID,Dao extends AbstractDao<Entity, ID>> {
    private EventExecutorGroup executorGroup;

    protected Dao dao;
    public AbstractAsyncDao(EventExecutorGroup executorGroup, Dao dao) {
        this.executorGroup = executorGroup;
        this.dao = dao;
    }
    
    public Dao getSyncDao() {
        return dao;
    }
    public void execute(ID id, Promise<?> promise, Runnable task) {
        EventExecutor executor = this.executorGroup.select(id.hashCode());
        executor.execute(() -> {
            try {
                task.run();
            } catch (Throwable e) {// 统一进行异常捕获，防止由于数据库查询的异常导到线程卡死
                log.error("数据库操作失败,userId:{}", id, e);
                if (promise != null) {
                    promise.setFailure(e);
                }
            }
        });
    }
    public void execute(ID id,  Runnable task) {
        EventExecutor executor = this.executorGroup.select(id.hashCode());
        executor.execute(() -> {
            try {
                task.run();
            } catch (Throwable e) {// 统一进行异常捕获，防止由于数据库查询的异常导到线程卡死
                log.error("数据库操作失败,userId:{}", id, e);
            }
        });
    }
    /**
     * 
     * 异步从数据库查找
     *
     */
    public Future<Optional<Entity>> findById(ID id, Promise<Optional<Entity>> promise) {
        this.execute(id, promise, () -> {
            Optional<Entity> playerOp = dao.findByIdFromCacheOrLoader(id);
            promise.setSuccess(playerOp);
        });
        return promise;
    }
    /**
     * 异步更新数据到数据库
     */
    public Promise<Boolean> saveOrUpdateToDB(ID id,Entity entity,Promise<Boolean> promise) {
        this.execute(id, promise, ()->{
            dao.saveOrUpdateToDB(entity);
            promise.setSuccess(true);
        });
        return promise;
    }
    /**
     * 异步更新数据到redis
     */
    public Promise<Boolean> saveOrUpdateToRedis(ID id,Entity entity,Promise<Boolean> promise) {
        this.execute(id,promise,()->{
           dao.saveOrUpdateToRedis(entity, id);
           promise.setSuccess(true);
        });
        return promise;
    }
    
}
